package cn.ixp.agent.transformer;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.List;

public class InjectMethodCostTimeTransformer implements ClassFileTransformer {
    private static Logger logger = LoggerFactory.getLogger(InjectMethodCostTimeTransformer.class);

    public static final List<String> injectCls = new ArrayList<>();

    static {
        injectCls.add("com/ylzinfo/apps/service/account");
        injectCls.add("com/ylzinfo/apps/common/dao/YktDAO");
        injectCls.add("com/ylzinfo/apps/common/dao/DatabaseConnectionManager");
        injectCls.add("com/ylzinfo/apps/facade");
        injectCls.add("com/ylzinfo/apps/trans/YktTrans");
        injectCls.add("com/ylzinfo/apps/unifiapi/UnifiapiContoller");
    }

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        boolean contains = false;
        for (int i = 0; i < injectCls.size(); i++) {
            if (className.contains(injectCls.get(i))) {
                contains = true;
            }
        }
        if (!contains) {
            return classfileBuffer;
        }
        logger.info("InjectMethodCostTimeTransformer transform invoke! " + className);
        String targetClassName = className.replaceAll("/", ".");
        try {
            final ClassPool classPool = ClassPool.getDefault();
            final CtClass clazz = classPool.get(targetClassName);
            for (CtMethod declaredMethod : clazz.getDeclaredMethods()) {

                declaredMethod.addLocalVariable("_time", CtClass.longType);
                // 进入时间
                String param1 = "_time=System.currentTimeMillis();";
                // 打印语句
                String param2 = "LOG.info(\"### " + declaredMethod.getDeclaringClass().getSimpleName() + "." + declaredMethod.getName() + "() cost:\"+(System.currentTimeMillis()-_time)) ;";
                declaredMethod.insertBefore(param1);
                declaredMethod.insertAfter(param2);
            }
            // 返回字节码，并且detachCtClass对象
            byte[] byteCode = clazz.toBytecode();
            //detach的意思是将内存中曾经被javassist加载过的Date对象移除，如果下次有需要在内存中找不到会重新走javassist加载
            clazz.detach();
            return byteCode;
        } catch (Exception e) {
            System.out.println("has error" + targetClassName);
            e.printStackTrace();
        }
        return null;
    }
}
